package com.xiaoyu.core.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.Map;
import java.util.Optional;

/**
 * jwt令牌生成工具
 * @author ：小鱼
 * @date ：Created in 2023/6/6
 **/
public class JwtUtil {
    /**
     * 令牌加密的秘钥
     */
    private String secret;

    /**
     * 令牌前缀Bearer
     */
    private String tokenPrefix;

    /**
     * 令牌主题
     */
    private String subject = "login-token";

    /**
     * 生成jwt令牌
     * @param payload 要生成令牌的主体内容
     */
    public String genToken(Map<String,Object> payload){
        //令牌的签发时间
        payload.put("iat",new Date());
        return Jwts.builder()
                //令牌主题,随便自己写
                .setSubject(this.subject)
                //jwt令牌主体内容
                .setClaims(payload)
                //令牌永久有效
                //.setExpiration(expire)
                //数字签名配置
                .signWith(
                        // 加密秘钥
                        Keys.hmacShaKeyFor(this.secret.getBytes()),
                        // 加密算法
                        SignatureAlgorithm.HS256)
                //打包生成令牌
                .compact();
    }

    /**
     * 解析令牌
     * @param token jwt令牌内容
     */
    public Claims parseToken(String token){
        if(!StringUtils.hasText(token)){
            throw new IllegalArgumentException("令牌不能为空!");
        }
        String jwt = Optional.of(token)
                .filter(t -> t.startsWith(this.tokenPrefix))
                .flatMap((t) -> Optional.of(t.replaceFirst(
                        String.format("%s%s", this.tokenPrefix, " "), "")))
                .orElseGet(()->token);

        Claims body = Jwts.parserBuilder()
                //设置秘钥
                .setSigningKey(Keys.hmacShaKeyFor(this.secret.getBytes()))
                //创建令牌解析器
                .build()
                //解析令牌
                .parseClaimsJws(jwt)
                //令牌解析通过,获取payload当中的数据
                .getBody();
        return body;
    }

    private JwtUtil(String secret, String tokenPrefix) {
        this.secret = secret;
        this.tokenPrefix = tokenPrefix;
    }

    /**
     * 创建jwt工具构建者
     */
    public static JjwtUtilBuilder builder(){
        return new JjwtUtilBuilder();
    }

    //构建者模式
    public static class JjwtUtilBuilder{
        //属性对象
        private JwtProperties jwtProperties;

        public JjwtUtilBuilder config(JwtProperties jwtProperties){
            this.jwtProperties = jwtProperties;
            return this;
        }

        /**
         * 构建JjwtUtil
         */
        public JwtUtil build(){
            return new JwtUtil(jwtProperties.getSecret(), jwtProperties.getHeader().getTokenPrefix());
        }
    }
}
